﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Apollo;

namespace AlgoMS
{
    public class AlgoMSContractFactory : IApolloStrategyFactory
    {
        public ApolloStrategy createNew(string id)
        {
            return new AlgoMSContract(id);
        }
    }

    public class AlgoMSContract : ApolloStrategy, IApolloMdListener
    {
        private IApolloMdProvider mdProvider;
        private IApolloTrader trader;
        private ApolloProductInfo productInfo;
        private ApolloMdField lastMd;

        private ApolloParamFrontAccount account;
        private ApolloParamInstrument instrId;
        private ApolloParamInt ratio;
        private ApolloParamInt longLim;
        private ApolloParamInt shortLim;
        private ApolloParamPrice buyThrd;
        private ApolloParamPrice sellThrd;
        private ApolloParamInt qty;
        private ApolloParamInt levelLim;
        private ApolloParamInt buyCheck;
        private ApolloParamInt sellCheck;
        private ApolloParamInt tolerance;
        private ApolloParamBool active;

        public AlgoMSContract(string id) : base(id)
        {
            account = new ApolloParamFrontAccount("account", (p) =>
            {
                bool wasWorking = this.isActive();
                if (wasWorking)
                {
                    stop();
                }
                Tuple<ApolloFront, ApolloAccount> ea = p.getValue();
                mdProvider = ea.Item1.getBestMdProvider();
                trader = ea.Item1.getTrader(ea.Item2);
                if(wasWorking)
                {
                    start();
                }
            });

            instrId = new ApolloParamInstrument("Instr", (p) =>
            {
                bool wasWorking = this.isActive();
                if(wasWorking)
                {
                    stop();
                }
                productInfo = mdProvider.getProductDictionary().getInstrumentInfo(p.getValue());
                if (wasWorking)
                {
                    start();
                }
            });

            ratio = new ApolloParamInt("Ratio");
            longLim = new ApolloParamInt("LongLim");
            shortLim = new ApolloParamInt("ShortLim");
            buyThrd = new ApolloParamPrice("BuyThrd");
            sellThrd = new ApolloParamPrice("SellThrd");
            qty = new ApolloParamInt("Qty");
            levelLim = new ApolloParamInt("LevelLim");
            buyCheck = new ApolloParamInt("BuyCheck");
            sellCheck = new ApolloParamInt("SellCheck");
            tolerance = new ApolloParamInt("Tolerance");
            active = new ApolloParamBool("on/off", "on", "off");

            registerParameter(active);
            registerParameter(account);
            registerParameter(instrId);
            registerParameter(ratio);
            registerParameter(longLim);
            registerParameter(shortLim);
            registerParameter(buyThrd);
            registerParameter(sellThrd);
            registerParameter(qty);
            registerParameter(levelLim);
            registerParameter(buyCheck);
            registerParameter(sellCheck);
            registerParameter(tolerance);

            lastMd = null;

        }

        public override List<Tuple<IApolloTrader, string>> getInstrumentList()
        {
            List<Tuple<IApolloTrader, string>> list = new List<Tuple<IApolloTrader, string>>();
            list.Add(new Tuple<IApolloTrader, string>(trader, instrId.getValue()));
            return list;
        }

        protected override bool startHandler()
        {
            return false;
        }

        protected override bool stopHandler()
        {
            return false;
        }

        public void startListenMD()
        {
            if (mdProvider != null)
            {
                mdProvider.addMdListener(this);
            }
        }

        public void stopListenMD()
        {
            if (mdProvider != null)
            {
                mdProvider.removeMdListener(this);
            }
        }

        public bool isActive()
        {
            return this.active.getValue();
        }

        public ApolloParamFrontAccount getAccount()
        {
            return this.account;
        }

        public IApolloTrader getTrader()
        {
            return trader;
        }

        public IApolloMdProvider getMdProvider()
        {
            return mdProvider;
        }

        public ApolloMdField getLastMd()
        {
            return this.lastMd;
        }

        public ApolloProductInfo getProductInfo()
        {
            return this.productInfo;
        }

        public string getInstrId()
        {
            return this.instrId.getValue();
        }

        public int getRatio()
        {
            return this.ratio.getValue();
        }

        public int getLongLim()
        {
            return this.longLim.getValue();
        }

        public int getShortLim()
        {
            return this.shortLim.getValue();
        }

        // 在Apollo中, BuyThrd和SellThrd如果小于0，原先-2，放大10000倍之后会变成-19999
        public long getBuyThrd()
        {
            if (this.buyThrd.getLongPrice() < 0)
                return this.buyThrd.getLongPrice() - 1;
            return this.buyThrd.getLongPrice();
        }

        public long getSellThrd()
        {
            if (this.sellThrd.getLongPrice() < 0)
                return this.sellThrd.getLongPrice() - 1;
            return this.sellThrd.getLongPrice();
        }

        public int getQty()
        {
            return this.qty.getValue();
        }

        public int getLevelLim()
        {
            return this.levelLim.getValue();
        }

        public int getBuyCheck()
        {
            return this.buyCheck.getValue();
        }

        public int getSellCheck()
        {
            return this.sellCheck.getValue();
        }

        public int getTolerance()
        {
            return this.tolerance.getValue();
        }

        public string[] getListeningInstrumentIds()
        {
            return new string[] { instrId.getValue() };
        }

        public void onMarketData(ApolloMdField data, ApolloExchangeEventContext context)
        {
            // ApolloGlobal.getCore().debugPrint("contract onMarketData {0} {1}", this.getInstrId(), data.ToString());
        }

        public void onMarketChanged(ApolloMdField data, int changeFlag, ApolloExchangeEventContext context)
        {
            this.lastMd = data;
            // ApolloGlobal.getCore().debugPrint("contract onMarketChanged {0} {1}", this.getInstrId(), data.ToString());
            if(this.getParent() != null)
            {
                ((AlgoMSStrategy)this.getParent()).onMarketChanged(data, changeFlag);
            }
        }

        public bool checkAccount()
        {
            string name = this.getProductInfo().ProductName;
            if (!this.getInstrId().Contains(name))
            {
                ApolloGlobal.getCore().debugPrint("******警告：AlgoMS参数设置错误，{0}的用户账户与合约不对应******", this.getInstrId());
                return false;
            }
            return true;
        }

        public bool checkContract()
        {
            
            if (this.getRatio() > 0)
            {
                if (this.getLongLim() < 0 || this.getShortLim() < 0)
                {
                    ApolloGlobal.getCore().debugPrint("******警告：AlgoMS参数设置错误，{0}的LongLim, ShortLim必须大于等于0******", this.getInstrId());
                    return false;
                }
                if (this.getBuyThrd() > this.getSellThrd())
                {
                    ApolloGlobal.getCore().debugPrint("******警告：AlgoMS参数设置错误，{0}的BuyThrd必须小于等于SellThrd******", this.getInstrId());
                    return false;
                }
                if (this.getLevelLim() < 0)
                {
                    ApolloGlobal.getCore().debugPrint("******警告：AlgoMS参数设置错误，{0}的LevelLim必须大于等于0******", this.getInstrId());
                    return false;
                }
                if (this.getQty() < 0)
                {
                    ApolloGlobal.getCore().debugPrint("******警告：AlgoMS参数设置错误，{0}的qty必须大于等于0******", this.getInstrId());
                    return false;
                }
                if (this.getTolerance() < 0)
                {
                    ApolloGlobal.getCore().debugPrint("******警告：AlgoMS参数设置错误，{0}的Tolerance必须大于等于0******", this.getInstrId());
                    return false;
                }
                if (this.getBuyCheck() < 0 || this.getSellCheck() < 0 )
                {
                    ApolloGlobal.getCore().debugPrint("******警告：AlgoMS参数设置错误，{0}的BuyCheck, SellCheck必须大于等于0******", this.getInstrId());
                    return false;
                }
            }
            else if (this.getRatio() == 0)
            {
                ApolloGlobal.getCore().debugPrint("******警告：AlgoMS参数设置错误，{0}的Ratio不能为0******", this.getInstrId());
                return false;
            }
            return true;
        }

    }
}
